﻿using GeneticAlgorithms.Genomes;
using GeneticAlgorithms.Operators.Crossover;
using GeneticAlgorithms.Tests.Utils;
using GeneticAlgorithms.Tools;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace GeneticAlgorithms.Tests.Operators.Crossover
{
    [TestClass]
    public class DoublePointCrossoverTest
    {
        [TestMethod]
        public void TestCross()
        {
            int length = 22;
            int[] flipPositions = new int[2] { 10, 5 };
            int i = 0;
            IGeneticRandomGenerator originalRnd = GeneticRandomGenerator.Default;
            Mock<IGeneticRandomGenerator> randomMock = new Mock<IGeneticRandomGenerator>();
            randomMock.Expect(r => r.Next(length)).Returns(() => flipPositions[i++]);
            randomMock.Expect(r => r.Next(length)).Returns(() => flipPositions[i++]);
            GeneticRandomGenerator.Default = randomMock.Object;
            CrossoverOperatorTestHelper<ArrayGenome<bool>, bool> helper =
                new CrossoverOperatorTestHelper<ArrayGenome<bool>, bool>();
            ArrayGenome<bool>[] parents = new ArrayGenome<bool>[2];
            parents[0] = helper.GetBoolGenome(length);
            parents[1] = helper.GetBoolGenome(length, false);
            ArrayGenome<bool>[] expected = new ArrayGenome<bool>[2];
            expected[0] = helper.GetBoolGenome(length, index => !IsBetween(index, flipPositions[1], flipPositions[0]));
            expected[1] = helper.GetBoolGenome(length, index => IsBetween(index, flipPositions[1], flipPositions[0]));
            ArrayGenome<bool>[] actual = new ArrayGenome<bool>[2];
            actual[0] = helper.GetBoolGenome(length);
            actual[1] = helper.GetBoolGenome(length);
            DoublePointCrossover<ArrayGenome<bool>, bool> target =
                new DoublePointCrossover<ArrayGenome<bool>, bool>();
            target.Cross(parents, actual);
            ExtraAssert.GenomeCollectionsMatch<ArrayGenome<bool>, bool>(expected, actual);
            GeneticRandomGenerator.Default = originalRnd;
        }

        private static bool IsBetween(int value, int inclusiveMinimum, int inclusiveMaximum)
        {
            return (value >= inclusiveMinimum) && (value < inclusiveMaximum);
        }
    }
}
